This demo shows how recursive DFS uses the call stack to manage the current path and when pre/post actions happen (discovery/finish).

dfs_recursive.py

def dfs(u):
    color[u] = GRAY           # discover (pre)
    time += 1; d[u] = time
    for v in adj[u]:
        if color[v] == WHITE:
            parent[v] = u; dfs(v)
    color[u] = BLACK          # finish (post)
    time += 1; f[u] = time
                    

Tip: GRAY = currently exploring; BLACK = finished. Discovery/finish times wrap children, forming the parenthesis structure.